﻿using Nijie.Network;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class TransformSyncManager : BaseSyncCtrl
{
    Camera mainCamera;
    static Dictionary<string, TransformSyncCtrl> items = new Dictionary<string, TransformSyncCtrl>();
    static HoloLens hostHoloLens;
    public static void SetHoloLens(HoloLens holoLens)
    {
        hostHoloLens = holoLens;
    }
    private void Start()
    {
        mainCamera = Camera.main;
    }
    private void Update()
    {
        Sync();
    }
    public static void AddTransformSyncCtrl(TransformSyncCtrl item, string id)
    {
        RemoveTransformSyncCtrl(item);
        try
        {
            items.Add(id, item);
        }
        catch (Exception e)
        {
            Debug.LogWarning(e);
        }
    }
    public static void RemoveTransformSyncCtrl(TransformSyncCtrl item)
    {
        string[] keys = new string[items.Keys.Count];
        int i = 0;
        foreach (string key in items.Keys)
        {
            keys[i] = key;
            i++;
        }
        foreach (string key in keys)
        {
            if (items[key].Equals(item))
                items.Remove(key);
        }
    }
    protected override void Deserialize(NetworkReader reader,RemoteDevice device)
    {
        bool isServer = reader.ReadBoolean();
        int count = reader.ReadInt32();
        TransformCache[] cache = new TransformCache[count];
        for (int i = 0; i < count; i++)
        {
            cache[i] = new TransformCache(reader);
        }
        foreach (TransformCache c in cache)
        {
            if (!items.ContainsKey(c.Key))
                continue;
            TransformSyncCtrl t = items[c.Key];
            if (t.active) t.gameObject.SetActive(c.ActiveSelf);
            if (t.scale) t.transform.localScale = c.LocalScale;
            if (!isServer || hostHoloLens == null) continue;
            if (t.rotation) t.transform.eulerAngles = hostHoloLens.transform.eulerAngles + c.DeltaAngles;
            if (t.position) t.transform.position = hostHoloLens.Position(c.DeltaPosition);
        }
    }

    protected override void Serialize(NetworkWriter writer)
    {
        writer.Write(SyncManager.IsServer);
        writer.Write(items.Count);
        foreach (KeyValuePair<string, TransformSyncCtrl> keyValue in items)
        {
            writer.Write(keyValue.Key);
            WriteItem(keyValue.Value, writer);
        }
    }
    void WriteItem(TransformSyncCtrl item, NetworkWriter writer)
    {
        writer.Write(item.active);
        writer.Write(item.gameObject.activeSelf);
        writer.Write(item.scale);
        writer.Write(item.transform.localScale);
        writer.Write(item.rotation);
        writer.Write(item.transform.eulerAngles - mainCamera.transform.eulerAngles);
        writer.Write(item.position);
        writer.Write(DeltaPosition(item.transform.position));
    }
    Vector3 DeltaPosition(Vector3 position)
    {
        Transform transform = mainCamera.transform;
        Vector3 v = position - transform.position;
        float x = Vector3.Dot(transform.right, v);
        float y = Vector3.Dot(transform.up, v);
        float z = Vector3.Dot(transform.forward, v);
        return new Vector3(x, y, z);
    }
    struct TransformCache
    {
        public string Key { get; set; }
        public bool Active { get; set; }
        public bool ActiveSelf { get; set; }
        public bool Scale { get; set; }
        public Vector3 LocalScale { get; set; }
        public bool Rotation { get; set; }
        public Vector3 DeltaAngles { get; set; }
        public bool Position { get; set; }
        public Vector3 DeltaPosition { get; set; }
        public TransformCache(NetworkReader reader)
        {
            Key = reader.ReadString();
            Active = reader.ReadBoolean();
            ActiveSelf = reader.ReadBoolean();
            Scale = reader.ReadBoolean();
            LocalScale = reader.ReadVector3();
            Rotation = reader.ReadBoolean();
            DeltaAngles = reader.ReadVector3();
            Position = reader.ReadBoolean();
            DeltaPosition = reader.ReadVector3();
        }
    }
    #region Init
    private static TransformSyncManager instance;
    public static TransformSyncManager Instance
    {
        get
        {
            return instance;
        }
    }
    /// <summary>
    /// Returns whether the instance has been initialized or not.
    /// </summary>
    public static bool IsInitialized
    {
        get
        {
            return instance != null;
        }
    }
    /// <summary>
    /// Base awake method that sets the singleton's unique instance.
    /// </summary>
    protected new void Awake()
    {
        if (instance != null)
        {
            Debug.LogErrorFormat("Trying to instantiate a second instance of singleton class {0}", GetType().Name);
        }
        else
        {
            instance = this;
            base.Awake();
        }
    }
    protected new void OnDestroy()
    {
        if (instance == this)
        {
            instance = null;
        }
        base.OnDestroy();
    }
    #endregion Init
}
